
//  Copyright (C) 2011 Luca Piccioni
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
// 
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections.Generic;
using System.Text;

namespace Derm.Raster
{
	/// <summary>
	/// Generic image informations.
	/// </summary>
	public class ImageInfo
	{
		#region Fundamentals

		/// <summary>
		/// Original image format.
		/// </summary>
		public ImageFormat ContainerFormat;

		/// <summary>
		/// Original image pixel type.
		/// </summary>
		public Pixel.Type PixelType
		{
			get { return (mOrigPixelType); }
			set {
				// Store original pixel format
				mOrigPixelType = value;
				// Check for real pixel format used to manage image pixels (@todo Are there any context dependencies issues?
				if (Pixel.IsSupportedSetDataFormat(value, value) == false) {
					// OpenGL cannot create texture having pixel format 'type' by submitting data having pixel format 'type'
					mRealPixelType = Pixel.GuessBestSupportedConvertion(mOrigPixelType);
				} else {
					// Extact match between data and texture pixel formats
					mRealPixelType = mOrigPixelType;
				}
			}
		}

		/// <summary>
		/// Image pixel type really used to pixel data storage.
		/// </summary>
		/// <remarks>
		/// 
		/// </remarks>
		public Pixel.Type RealPixelType
		{
			get { return (mRealPixelType); }
			set {
				if (value == Pixel.Type.None)
					throw new ArgumentException("invalid real pixel type", "value");
				// Override automatically determined real pixel type
				mRealPixelType = value;
			}
		}

		/// <summary>
		/// Determine whether the image shall be converted by software because not supported by hardware.
		/// </summary>
		public bool RequiresSoftwareConversion
		{
			get {
				return (PixelType != RealPixelType);
			}
		}

		/// <summary>
		/// RasterImage width (in pixels).
		/// </summary>
		public uint Width;

		/// <summary>
		/// RasterImage height (in pixels);
		/// </summary>
		public uint Height;

		/// <summary>
		/// Original image pixel type.
		/// </summary>
		private Pixel.Type mOrigPixelType;

		/// <summary>
		/// Real image pixel type.
		/// </summary>
		/// <remarks>
		/// On recent platforms this member shall be equal to <see cref="mOrigPixelType"/>
		/// </remarks>
		private Pixel.Type mRealPixelType;

		#endregion

		#region Generic Tags

		/// <summary>
		/// The complete list of tags defined in this ImageInfo.
		/// </summary>
		public uint TagCount
		{
			get {
				return ((uint)mTags.Values.Count);
			}
		}

		/// <summary>
		/// The complete list of Tags included in this ImageInfo.
		/// </summary>
		public IEnumerable<KeyValuePair<string, object>> Tags
		{
			get {
				foreach (KeyValuePair<string, object> pair in mTags)
					yield return (pair);
			}
		}

		/// <summary>
		/// Determine whether this ImageInfo has defined a specific tag.
		/// </summary>
		/// <param name="id">
		/// A <see cref="System.String"/> which identify a tag.
		/// </param>
		public bool HasTag(string id)
		{
			if (id == null)
				throw new ArgumentNullException("id");

			return (mTags.ContainsKey(id));
		}

		/// <summary>
		/// Set a tag to this ImageInfo
		/// </summary>
		/// <param name="id">
		/// A <see cref="System.String"/> which identify a tag.
		/// </param>
		/// <param name="value">
		/// A <see cref="System.Object"/> which define the tag value.
		/// </param>
		public void SetTag(string id, object value)
		{
			mTags[id] = value;
		}

		/// <summary>
		/// Get a tag value from this ImageInfo.
		/// </summary>
		/// <typeparam name="T">
		/// The type of the tag value.
		/// </typeparam>
		/// <param name="id">
		/// A <see cref="System.String"/> which identify a tag.
		/// </param>
		/// <returns>
		/// It returns the value of the tag.
		/// </returns>
		public T GetTag<T>(string id)
		{
			object tag;

			if (HasTag(id) == false)
				throw new ArgumentException(String.Format("tag {0} not defined", id));

			// Get the tag object
			tag = mTags[id];

			// Check tag type
			if (!(tag is T))
				throw new ArgumentException(String.Format("tag {0} is not a {1}", id, typeof(T).Name));

			return ((T)tag);
		}

		/// <summary>
		/// Generic tag collection.
		/// </summary>
		private Dictionary<string, object> mTags = new Dictionary<string,object>();

		#endregion

		#region Conventional Tags Identifiers

		/// <summary>
		/// The Image comment.
		/// </summary>
		public static readonly String TagComment = "Comment";

		/// <summary>
		/// The person who has acquired the Image.
		/// </summary>
		public static readonly String TagAcquisitionArtist = "AcquisitionArtist";

		/// <summary>
		/// The device used for acquiring the Image.
		/// </summary>
		public static readonly String TagAcquisitionDevice = "AcquisitionDevice";

		/// <summary>
		/// The device used for acquiring the Image.
		/// </summary>
		public static readonly String TagGamma = "Gamma";

		#endregion
	}
}
